<?php
/**
 * Created by IntelliJ IDEA.
 * User: ty42
 * Date: 1/13/16
 * Time: 4:15 PM
 */

defined('BASEPATH') OR exit('No direct script access allowed');

/**
 * Class Push_std
 */
class Push_std extends CI_Model
{
    const PUSH_SERVICE_BASE = "base";
    const PUSH_SERVICE_JPUSH = "jpush";
    const PUSH_SERVICE_MIPUSH = "mipush";

    const MACHINE_TYPE_IOS = '2002';
    const MACHINE_TYPE_ANDROID = '3001';
    
    
    const PUSH_TYPE_POST_CONTENT    = "0";
    const PUSH_TYPE_DISSUBJECT      = "1";
    const PUSH_TYPE_SHORT_INFO      = "2";
    const PUSH_TYPE_NEW_POST        = "3";
    const PUSH_TYPE_HELP_SHOW       = "4";
    const PUSH_TYPE_WEEKLY_HOT      = "5";


    protected $name = self::PUSH_SERVICE_BASE;

    function __construct(){}

    /**
     * 根据注册 ID 发送 PUSH
     *
     * @param string $reg_id
     * @param string $message
     * @param array $extras
     * @return array
     */
    public function SendByRegistrationID($reg_id, $message, $extras)
    {
        return array("name"=>$this->name, "num"=>0, "msg_id"=>0, "result"=>"");
    }

    /**
     * 根据别称发送 PUSH
     *
     * @param $alias
     * @param $message
     * @param array $extras
     * @param string $typ
     * @return array
     */
    public function SendByAlias($alias, $message, $extras, $typ)
    {
        return array("name"=>$this->name, "num"=>0, "msg_id"=>0, "result"=>"");
    }

    /**
     * 根据别称数组发送 PUSH
     *
     * @param $alias_arr
     * @param $message
     * @param array $extras
     * @return array
     */
    public function SendByAliasMore($alias_arr, $message, $extras)
    {
        return array("name"=>$this->name, "num"=>0, "msg_id"=>0, "result"=>"");
    }

    /**
     * 根据标签数组发送 PUSH
     *
     * @param $tag_arr
     * @param $message
     * @param array $extras
     * @return array
     */
    public function SendByTags($tag_arr, $message, $extras) {
        return array("name"=>$this->name, "num"=>0, "msg_id"=>0, "result"=>"");
    }
}


class Jpush_std extends Push_std
{
    protected $name = self::PUSH_SERVICE_JPUSH;

    function __construct()
    {
        $this->load->library('jpushmd');
    }

    /**
     * 根据注册 ID 发送 PUSH
     *
     * @param string $reg_id
     * @param string $message
     * @param $extras
     * @return array 失败时 msg_id 为 0
     */
    public function SendByRegistrationID($reg_id, $message, $extras)
    {
        $msg_id = 0;
        $err_msg = "";
        try {
            $res_obj = $this->jpushmd->SendByRegistrationID(array($reg_id), $message, $extras);
            $msg_id = $res_obj->msg_id;
        }
        catch (Exception $e) {
            $err_msg = $e->getMessage();
        }

        return array("name"=>$this->name, "num"=>1, "msg_id"=>$msg_id, "result"=>$err_msg);
    }

    /**
     * 根据别称发送 PUSH
     *
     * @param $alias
     * @param $message
     * @param $extras
     * @param string $typ
     * @return array 失败时 msg_id 为 0
     */
    public function SendByAlias($alias, $message, $extras, $typ)
    {
        $msg_id = 0;
        $err_msg = "";
        try {
            $res_obj = $this->jpushmd->SendByAlias($alias, $message, $extras);
            $msg_id = $res_obj->msg_id;
        }
        catch (Exception $e) {
            $err_msg = $e->getMessage();
        }

        return array("name"=>$this->name, "num"=>1, "msg_id"=>$msg_id, "result"=>$err_msg);
    }

    /**
     * 根据别称数组发送 PUSH
     *
     * @param $alias_arr
     * @param $message
     * @param $extras
     * @return array
     */
    public function SendByAliasMore($alias_arr, $message, $extras)
    {
        $msg_id = 0;
        $err_msg = "";
        try {
            $res_obj = $this->jpushmd->SendByAliasMore($alias_arr, $message, $extras);
            $msg_id = $res_obj->msg_id;
        }
        catch (Exception $e) {
            $err_msg = $e->getMessage();
        }

        return array("name"=>$this->name, "num"=>1, "msg_id"=>$msg_id, "result"=>$err_msg);
    }

    /**
     * 根据标签数组发送 PUSH
     *
     * @param $tag_arr
     * @param $message
     * @param array $extras
     * @return array
     */
    public function SendByTags($tag_arr, $message, $extras)
    {
        $msg_id = 0;
        $err_msg = "";
        try {
            $res_obj = $this->jpushmd->SendByTagMore($tag_arr, $message, $extras);
            $msg_id = $res_obj->msg_id;
        }
        catch (Exception $e) {
            $err_msg = $e->getMessage();
        }

        return array("name"=>$this->name, "num"=>1, "msg_id"=>$msg_id, "result"=>$err_msg);
    }
}


if(!defined('MI_PUSH_ENVIRONMENT_IOS')) {
    define('MI_PUSH_ENVIRONMENT_IOS', 'production');
}



use xmpush\Builder;
use xmpush\Constants;
use xmpush\IOSBuilder;
use xmpush\Sender;

include_once(APPPATH.'libraries/mipush_sdk/autoload.php');

class Mipush_std extends Push_std
{
    protected $name = self::PUSH_SERVICE_MIPUSH;

    const REG_ID_LEN_ANDROID = 108;
    const REG_ID_LEN_IOS = 128;

    const REG_ID_LEN_NEW = 44;

    function __construct()
    {
        $this->load->library('jpushmd');
        $this->load->model('userm');
    }

    /**
     * 根据注册 ID 发送 PUSH
     *
     * @param string $reg_id
     * @param string $message
     * @param string $extras
     * @return array 失败时 msg_id 为 0
     */
    public function SendByRegistrationID($reg_id, $message, $extras)
    {
        $typ_lst = array(self::MACHINE_TYPE_ANDROID, self::MACHINE_TYPE_IOS);
        $result = array();

        foreach ($typ_lst as $typ) {
            $msg_obj = $this->buildMsgByTyp($message, $extras, $typ);

            $sender = new Sender($this->retAppSecretByTyp($typ));

            // 根据注册 ID 发送
            $result_obj = $sender->send($msg_obj, $reg_id);
            $msg_id = $this->parseMsgIDFromReqData($result_obj->getRaw());

            $result[] = array("name"=>$this->name, "num"=>1, "msg_id"=>$msg_id,
                "push_typ"=>$typ, "result"=>$result_obj->getRaw());
        }

        return $result;
    }

    /**
     * 根据别称发送 PUSH
     *
     * @param $alias
     * @param $message
     * @param $extras
     * @param string $typ
     * @return array 失败时 msg_id 为 0
     */
    public function SendByAlias($alias, $message, $extras, $typ)
    {
        if ($typ != self::MACHINE_TYPE_ANDROID && $typ != self::MACHINE_TYPE_IOS) {
            return array("name"=>$this->name, "num"=>1, "msg_id"=>0);
        }


        $msg_obj = $this->buildMsgByTyp($message, $extras, $typ);


        $sender = new Sender( $this->retAppSecretByTyp($typ) );

        // 根据别名发送
        $result_obj = $sender->sendToAlias($msg_obj, $alias);

        $msg_id = $this->parseMsgIDFromReqData($result_obj->getRaw());

        return array("name"=>$this->name, "num"=>1, "msg_id"=>$msg_id, "result"=>$result_obj->getRaw());
    }

    /**
     * @param $alias_arr
     * @param $message
     * @param $extras
     * @param string $typ self::MACHINE_TYPE_ANDROID|self::MACHINE_TYPE_IOS
     * @return array
     */
    public function SendByAliasMoreAndTpe($alias_arr, $message, $extras, $typ)
    {
        if (empty($alias_arr)) {
            return array("name"=>$this->name, "num"=>0, "msg_id"=>0, "push_typ"=>$typ);
        }

        $msg_obj = $this->buildMsgByTyp($message, $extras, $typ);

        $sender = new Sender( $this->retAppSecretByTyp($typ) );

        // 根据别名数组发送
        $result_obj = $sender->sendToAliases($msg_obj, $alias_arr);

        $msg_id = $this->parseMsgIDFromReqData($result_obj->getRaw());

        return array("name"=>$this->name, "num"=>count($alias_arr), "msg_id"=>$msg_id,
            "push_typ"=>$typ, "result"=>$result_obj->getRaw());
    }

    /**
     * 根据别称数组发送 PUSH
     *
     * @param $alias_arr
     * @param $message
     * @param $extras
     * @return array
     */
    public function SendByAliasMore($alias_arr, $message, $extras)
    {
        $user_info_arr = $this->userm->getUserInfoByIds($alias_arr);

        $alias_android_arr = array();
        $alias_ios_arr = array();
        foreach ($user_info_arr as $user_info) {
            if ($user_info["productid"] == self::MACHINE_TYPE_ANDROID) {
                $alias_android_arr[] = $user_info["id"];
            }

            if ($user_info["productid"] == self::MACHINE_TYPE_IOS) {
                $alias_ios_arr[] = $user_info["id"];
            }
        }

        $result = array();

        if (!empty($alias_android_arr)) {
            $result[] = $this->SendByAliasMoreAndTpe($alias_android_arr, $message, $extras, self::MACHINE_TYPE_ANDROID);
        }

        if (!empty($alias_ios_arr)) {
            $result[] = $this->SendByAliasMoreAndTpe($alias_ios_arr, $message, $extras, self::MACHINE_TYPE_IOS);
        }

        return $result;
    }

    /**
     * 根据标签数组发送 PUSH
     *
     * @param $tag_arr
     * @param $message
     * @param array $extras
     * @return array
     */
    public function SendByTags($tag_arr, $message, $extras)
    {
        $result = array();

        $typ_lst = array(self::MACHINE_TYPE_ANDROID, self::MACHINE_TYPE_IOS);

        if (count($tag_arr) <= 5) {

            foreach($typ_lst as $typ) {
                $msg_obj = $this->buildMsgByTyp($message, $extras, $typ);
                $sender = new Sender( $this->retAppSecretByTyp($typ) );

                $result_obj = $sender->multiTopicBroadcast($msg_obj, $tag_arr, Constants::UNION);

                $msg_id = $this->parseMsgIDFromReqData($result_obj->getRaw());

                $result[] = array("name"=>$this->name, "num"=>count($tag_arr), "msg_id"=>$msg_id,
                    "push_typ"=>$typ, "result"=>$result_obj->getRaw());
            }

            return $result;
        }

        // 最多 5 个
        $result = $this->SendByTags(array_slice($tag_arr, 0, 5), $message, $extras);

        // 递归处理, 五条以后的部分
        $result_left = $this->SendByTags(array_slice($tag_arr, 5), $message, $extras);
        foreach($result_left as $itm) {
            $result[] = $itm;
        }

        return $result;
    }

//    // 由于mipush改变id生成规则, 本方法失效
//    // 根据注册 ID 返回机型
//    protected function retWhichTypByRegID($reg_id) {
//        if (strlen($reg_id) > self::REG_ID_LEN_ANDROID) {
//            return self::MACHINE_TYPE_IOS;
//        }
//
//        return self::MACHINE_TYPE_ANDROID;
//    }

    // 根据机型 ID 返回机型
    protected function retWhichTypByProductID($product_id) {
        if ($product_id == self::MACHINE_TYPE_IOS) {
            return self::MACHINE_TYPE_IOS;
        }

        return self::MACHINE_TYPE_ANDROID;
    }

    // 根据机型返回 sdk 密钥
    protected function retAppSecretByTyp($typ) {
        if ($typ == self::MACHINE_TYPE_IOS) {
            return MI_PUSH_SECRET_IOS;
        }

        return MI_PUSH_SECRET_ANDROID;
    }

    // 根据机型返回 sdk package_id bundle_id
    protected function retAppPkgIDByTyp($typ) {
        if ($typ == self::MACHINE_TYPE_IOS) {
            return MI_PUSH_BUNDLE_ID_IOS;
        }

        return MI_PUSH_PACKAGE_ANDROID;
    }

    /**
     * 根据机型生成待发送消息
     *
     * @param $msg
     * @param array $extra
     * @param $typ
     * @param string $title
     * @return \xmpush\Message
     */
    protected function buildMsgByTyp($msg, $extra = array(), $typ, $title = "轻盈医学") {
        if ($typ == self::MACHINE_TYPE_IOS) {
            if (MI_PUSH_ENVIRONMENT_IOS != 'production') {
                // 测试环境, 仅 iOS
                Constants::useSandbox();
            } else {
                Constants::useOfficial();
            }

            $message = new IOSBuilder();

            // $message->soundUrl('default');
            // $message->badge('4');
            foreach ($extra as $k=>$v) {
                $message->extra($k, $v);
            }
        } else {
            Constants::useOfficial();
            Constants::setPackage($this->retAppPkgIDByTyp(self::MACHINE_TYPE_ANDROID));
            $payload = json_encode($extra);

            $message = new Builder();

            $message->passThrough(0);
            $message->payload($payload); // 对于预定义点击行为，payload会通过点击进入的界面的intent中的extra字段获取，而不会调用到onReceiveMessage方法。
//            $message->extra(Builder::notifyEffect, 2); // 此处设置预定义点击行为，不传为自定义跳转; 1为打开app
            $message->extra(Builder::notifyForeground, 1);
            $message->notifyId(0);
            $message->title($title);
        }

        $message->description($msg);
        $message->build();

        return $message;
    }

    /**
     * 从接口返回中解析出消息 ID
     *
     * @param array $data
     * @return int
     */
    protected function parseMsgIDFromReqData($data) {
        if ($data["code"] != 0) {
            return 0;
        }

        $msg_id = 0;
        if (isset($data["data"]["id"])) {
            $msg_id = $data["data"]["id"];
        }
        return $msg_id;
    }
}



class Pushm extends CI_Model
{
    protected $_push_instances = null;

    function __construct()
    {
        $this->load->model('userm');
    }

    /**
     * @param $service_name
     * @return Jpush_std|Mipush_std
     */
    public function getPushInstances($service_name)
    {
        if (!isset($this->_push_instances[$service_name])) {

            if ($service_name == Push_std::PUSH_SERVICE_JPUSH) {
                $this->_push_instances[$service_name] = new Jpush_std();
            }
            elseif ($service_name == Push_std::PUSH_SERVICE_MIPUSH) {
                $this->_push_instances[$service_name] = new Mipush_std();
            }
        }

        return $this->_push_instances[$service_name];
    }


    /**
     * 根据注册 ID 判断是否是 Jpush 注册 ID
     *
     * @param $reg_id
     * @return boolean
     */
    public function retPushServiceByRegID($reg_id) {
        // mipush 旧版
        if (substr($reg_id, 0, 3) == 'd//' && strlen($reg_id) >= Mipush_std::REG_ID_LEN_ANDROID) {
            return Push_std::PUSH_SERVICE_MIPUSH;
        }

        // mipush 新版
        if (strlen($reg_id) == Mipush_std::REG_ID_LEN_NEW) {
            return Push_std::PUSH_SERVICE_MIPUSH;
        }

        return Push_std::PUSH_SERVICE_JPUSH;
    }

    /**
     * 根据注册 ID 判断采用哪种 push
     *
     * @param $reg_id
     * @return Jpush_std|Mipush_std
     */
    public function retPushObjByRegID($reg_id) {
        $service_name = $this->retPushServiceByRegID($reg_id);

        return $this->getPushInstances($service_name);
    }

    protected function processExtras($extras)
    {
        $result = $extras;
        if (isset($extras["post_id"])) {
            $post_id = $extras["post_id"];

            if (!isset($extras["type"])) {
                $result["type"] = 0;
            }

            $this->load->model('postm');
            $this->unset_arr = array();
            // 作部分兼容处理
            if (!$this->uid) {
                $this->uid = $this->postm->get_post_author_id($post_id);
                $this->unset_arr[] = "uid";
            }
            if (!$this->softversion) {
                $this->softversion = DEFAULT_VERSION_FOR_PUSH;
                $this->unset_arr[] = "softversion";
            }
            if (!$this->pid) {
                $this->pid = '3001';
                $this->unset_arr[] = "pid";
            }
            
            // 相当于先确保缓存生效
            $cont = $this->postm->get_one_post_4_search_for_2_1($post_id, '', 1);
            $post_type_extend = isset($cont["post_type_extend"]) ? $cont["post_type_extend"] : 3;
            if ($post_type_extend == 4 || $post_type_extend == 5) {
                $result["did"] = $post_type_extend;
            }
        }

        return $result;
    }

    protected function cleanUpTmpVars()
    {
        if (isset($this->unset_arr) && is_array($this->unset_arr)) {
            foreach ($this->unset_arr as $k) {
                unset($this->$k);
            }
            unset($this->unset_arr);
        }
    }

    // 根据注册 ID 发 push
    public function sendByRegID($reg_id, $message, $extras)
    {
        $logstr = 'sendByRegID reg_id:' . $reg_id ."|message:" . $message . '|extras:' . json_encode($extras) . '|';
        $extras = $this->processExtras($extras);

        $push_std_obj = $this->retPushObjByRegID($reg_id);
        $result = $push_std_obj->SendByRegistrationID($reg_id, $message, $extras);

        $this->cleanUpTmpVars();
        w_log($logstr . 'result:' . json_encode($result));
        return $result;
    }

    // 根据用户 ID 发 push
    public function sendByUserID($user_id, $message, $extras)
    {
        $logstr = 'sendByUserID user_id:' . $user_id ."|message:" . $message . '|extras:' . json_encode($extras) . '|';
        $extras = $this->processExtras($extras);

        $user_info = $this->userm->getUserInfoById($user_id);

        $push_std_obj = $this->retPushObjByRegID($user_info["registrationID"]);
        $result = $push_std_obj->SendByAlias($user_id, $message, $extras, $user_info["productid"]);

        $this->cleanUpTmpVars();
        w_log($logstr . 'result:' . json_encode($result));
        return $result;
    }

    /**
     * 根据用户 ID 数组发 push
     *
     * @param $user_id_arr
     * @param $message
     * @param $extras
     * @return array
     */
    public function sendByUserIDArr($user_id_arr, $message, $extras)
    {
        $logstr = 'sendByUserIDArr user_id_arr:' . json_encode($user_id_arr) ."|message:" . $message . '|extras:' . json_encode($extras) . '|';
        $extras = $this->processExtras($extras);

        $result = array();

        if (count($user_id_arr) <= 1024) {
            $reg_id_arr = $this->userm->selectRegIDArrByUserIDArr($user_id_arr);

            $jpush_user_id_arr = array();
            $mipush_user_id_arr = array();

            foreach ($reg_id_arr as $reg_id => $itm) {
                $reg_typ = $this->retPushServiceByRegID($reg_id);
                if ($reg_typ == Push_std::PUSH_SERVICE_JPUSH) {
                    array_push($jpush_user_id_arr, $itm["id"]);
                }

                elseif ($reg_typ == Push_std::PUSH_SERVICE_MIPUSH) {
                    array_push($mipush_user_id_arr, $itm["id"]);
                }
            }

            if (!empty($jpush_user_id_arr)) {
                $push_obj = $this->getPushInstances(Push_std::PUSH_SERVICE_JPUSH);

                $result[] = $push_obj->SendByAliasMore($jpush_user_id_arr, $message, $extras);
            }

            if (!empty($mipush_user_id_arr)) {
                $push_obj = $this->getPushInstances(Push_std::PUSH_SERVICE_MIPUSH);

                $result[] = $push_obj->SendByAliasMore($mipush_user_id_arr, $message, $extras);
            }

            return $result;
        }

        // 递归处理,前一千条
        $result = $this->sendByUserIDArr(array_slice($user_id_arr, 0, 1000), $message, $extras);

        // 递归处理,一千条以后的部分
        $result_left = $this->sendByUserIDArr(array_slice($user_id_arr, 1000), $message, $extras);
        foreach($result_left as $itm) {
            $result[] = $itm;
        }


        $this->cleanUpTmpVars();
        w_log($logstr . 'result:' . json_encode($result));
        return $result;
    }

    public function SendByTags($tag_arr, $message, $extras) {
        $logstr = 'SendByTags tag_arr:' . json_encode($tag_arr) ."|message:" . $message . '|extras:' . json_encode($extras) . '|';
        $extras = $this->processExtras($extras);

        $result = array();

        $push_obj = $this->getPushInstances(Push_std::PUSH_SERVICE_JPUSH);
        $result[] = $push_obj->SendByTags($tag_arr, $message, $extras);

        $push_obj = $this->getPushInstances(Push_std::PUSH_SERVICE_MIPUSH);
        $result_mi = $push_obj->SendByTags($tag_arr, $message, $extras);
        foreach ($result_mi as $itm) {
            $result[] = $itm;
        }

        $this->cleanUpTmpVars();
        w_log($logstr . 'result:' . json_encode($result));
        return $result;
    }

    /**
     * 
     * push type 说明:
     * $type=0, $post_id, 推送帖子
     * $type=1, $did, 推送专题
     * $type=2, $uid, 推送个人中心
     * $type=3, 推送进入发帖界面
     * $type=4, $did, 推送帮助活动页 http://www.medical-lighter.com/help/help_show/{$did}
     * $type=5, $did, 推送周热帖活动页 http://www.medical-lighter.com/index/app_top10/{$did}
     * 
     * @param $type
     * @param $post_id
     * @param $did
     * @param $uid
     * @return array
     */
    public function getPostExtras($type, $post_id, $did, $uid = 0)
    {
        $extras = array();
        if ($post_id) {
            $extras = array("type" => Push_std::PUSH_TYPE_POST_CONTENT, "post_id" => $post_id);
        }
        elseif ($type == 2 && $uid) {
            $extras = array("type" => Push_std::PUSH_TYPE_SHORT_INFO, "uid" => $uid);
        }
        elseif ($type == 3) {
            $extras = array("type" => Push_std::PUSH_TYPE_NEW_POST);
        }
        elseif ($did && in_array($type, [Push_std::PUSH_TYPE_DISSUBJECT, Push_std::PUSH_TYPE_HELP_SHOW, Push_std::PUSH_TYPE_WEEKLY_HOT])) {
            $extras = array("type" => strval($type), "did" => $did);
        }
        return $extras;
    }
}